﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib.CSG
{

    struct isct_ray_triangle_result
    {
        double t;
        Vec3 bary;
    };
    static class Utils
    {
        public const int RAND_MAX = 0x7fff;
        public static Random rnd = new Random();
        internal static double triArea(Vec3 a, Vec3 b, Vec3 c)
        {
            return new Vec3().CrossVectors(b - a, c - a).Length();
        }
        public static double drand(double min, double max)
        {
            const double invMAX = 1.0 / RAND_MAX;
            double rand0to1 = rnd.Next() * invMAX;
            return (max - min) * rand0to1 + min;
        }
        public static void swap(ref int a, ref int b)
        {
            var c = a;
            a = b;
            b = c;
        }
        public static void swap(Vec3 a, Vec3 b)
        {
            var c = a.clone();
            a.copy(b);
            b.copy(c);
        }
        public static void swap<T>(IList<T> list, int a, int b)
        {
            var c = list[a];
            list[a] = list[b];
            list[b] = c;
        }




        public static bool isct_ray_triangle(
            Ray3 ray,
            Vec3 va,
            Vec3 vb,
            Vec3 vc,
            ref double t,
            ref Vec3 bary
        )
        {

            // re-center the problem at the base point of the ray
            va -= ray.p;
            vb -= ray.p;
            vc -= ray.p;

            // Then compute volumes of tetrahedra spanning
            //  * the base point / ray direction line segment
            //  * an edge of the triangle
            // Keeping orientations in mind...
            double volAB = Vec3.det(va, vb, ray.r);
            double volBC = Vec3.det(vb, vc, ray.r);
            double volCA = -Vec3.det(va, vc, ray.r);
            // then also compute the volume of tet with the entire triangle as a face...
            double volABC = Vec3.det(va, vb, vc);
            // if any of the signs of the edge tests
            // disagree with the sign of the whole triangle, then
            // the ray does not pass through the triangle
            if (volAB * volABC < 0 ||
               volBC * volABC < 0 ||
               volCA * volABC < 0) return false;

            // otherwise, compute the t - value for the ray to intersect
            // if this is negative, then the client can detect that the
            // ray would have to travel backwards to hit the triangle in question.
            double edgeSum = volAB + volBC + volCA;
            if (edgeSum == 0) return false;
            t = volABC / (volAB + volBC + volCA);
            if (t <= 0) return false;

            bary = new Vec3(volBC / edgeSum, volCA / edgeSum, volAB / edgeSum);
            return true;
        }

        public static void ENSURE(bool value)
        {
            if (!value)
            {

            }
        //      std::cerr << "ENSURE FAILED at " \
        //          << __FILE__ << ", line #" << __LINE__ << ":\n" \
        //          << "    " << #STATEMENT << std::endl; \
        //err()     << "ENSURE FAILED at " \
        //          << __FILE__ << ", line #" << __LINE__ << ":\n" \
        //          << "    " << #STATEMENT << std::endl; \
        }

    }
}
